#include "timer.h"


#ifdef KEY_DEBUGB
#define dbg_print(fmt, ...)			\
	do{								\
		printk("KEY: ");			\
		printk(fmt, ##__VA_ARGS__);	\
		printk("\r\n");				\
	}while(0)
#else
#define dbg_print(fmt, ...) 
#endif

static int gpio;
static unsigned int irq;
static int is_update;
static char key_status;
DECLARE_WAIT_QUEUE_HEAD(r_wq);

#ifdef USING_HRTIMER
static struct hrtimer hrtimer;
#else
static struct timer_list timer;
#endif

static irqreturn_t key_handler(int irq, void *dev)
{
#ifdef USING_HRTIMER
	//启动hrtimer
	hrtimer_start(&hrtimer, ktime_set(0, 10000), HRTIMER_MODE_REL);
#else
	//设置定时器到期时间，如果定时器没有注册则会将其注册
	mod_timer(&timer, jiffies + msecs_to_jiffies(10));
#endif
	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

#ifdef USING_HRTIMER
static enum hrtimer_restart hrtimer_func(struct hrtimer *hrtimer)
{
	printk("hrtimer_func\r\n");
	//读取GPIO状态
	key_status = gpio_get_value(gpio) + '0';
	//标记按键状态已经更新
	is_update = 1;
	//唤醒读按键的进程
	wake_up_interruptible(&r_wq);
	
	//返回HRTIMER_NORESTART，表示不需要重启定时器
	return HRTIMER_NORESTART;
}
#else
static void timer_func(struct timer_list *tm)
{
	printk("timer_func\r\n");
	//读取GPIO状态
	key_status = gpio_get_value(gpio) + '0';
	//标记按键状态已经更新
	is_update = 1;
	//唤醒读按键的进程
	wake_up_interruptible(&r_wq);
}
#endif

static ssize_t key_read(struct file *file, char __user *buffer, size_t lenght, loff_t *pos)
{
	if(is_update == 0)
	{
		//以非阻塞式打开
		if(file->f_flags & O_NONBLOCK)
			return -EAGAIN;

		//挂起当前进程到等待队列，能被信号唤醒
		if(wait_event_interruptible_exclusive(r_wq, is_update))
			return -ERESTARTSYS;
	}

	//将FIFO中的数据读取到应用层
	if(copy_to_user(buffer, &key_status, 1))
	{
		dbg_print("Bad address\r\n");
		return -EFAULT;
	}

	//改变按键更新状态
	is_update = 0;

	return 1;
}

static struct file_operations ops = {
	.owner = THIS_MODULE,
	.read = key_read,
};

static struct miscdevice key_misc = {
	.name = MY_KEY_NAME,
	.minor = MY_KEY_MINOR,
	.fops = &ops,
};

static int key_probe(struct platform_device *pled_dev)
{
	int result;
	uint32_t irq_flags;

	printk("**%s probe**\r\n", pled_dev->name);
	//按键状态未更新
	is_update= 0;

	//获取GPIO号
	gpio = of_get_named_gpio(pled_dev->dev.of_node, "key-gpio", 0);
	if(gpio < 0)
	{
		dbg_print("get gpio failed\r\n");
		return gpio;
	}
	//申请GPIO
	result = gpio_request(gpio, "key");
	if(result != 0)
	{
		dbg_print("request gpio failed\r\n");
		return result;
	}
	//设置GPIO为输入
	gpio_direction_input(gpio);

	//初始化消抖定時器
#ifdef USING_HRTIMER
	hrtimer_init(&hrtimer, CLOCK_BOOTTIME, HRTIMER_MODE_REL);
	hrtimer.function = hrtimer_func;
#else
	timer_setup(&timer, timer_func, 0);
	// add_timer(&timer);
#endif

	//获取中断号
	irq = irq_of_parse_and_map(pled_dev->dev.of_node, 0);
	//获取中断触发方式
	irq_flags = irq_get_trigger_type(irq);
	if(irq_flags == IRQF_TRIGGER_NONE)
		irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
	//注册中断
	result = request_irq(irq, key_handler, irq_flags, "key", (void*)irq);
	if(result != 0)
	{
		dbg_print("request irq failed\r\n");
		return result;
	}

	//注册混杂设备
	result = misc_register(&key_misc);
	if(result != 0)
	{
		dbg_print("register misc failed\r\n");
		return result;
	}
	return 0;
}

static int key_remove(struct platform_device *pled_dev)
{
	printk("**%s remove**\r\n", pled_dev->name);

	//注销混杂设备
	misc_deregister(&key_misc);
	//释放中断处理函数
	free_irq(irq, (void*)irq);
	//删除定时器
#ifdef USING_HRTIMER
	hrtimer_cancel(&hrtimer);
#else
	del_timer_sync(&timer);
#endif
	//释放GPIO
	gpio_free(gpio);
	return 0;
}

/* 匹配列表，用于设备树和驱动进行匹配 */
static struct of_device_id key_of_match[] = {
	{.compatible = "intr_key"},
	{},
};

static struct platform_driver key_drv = { 
	.driver = {
		.name = "intr_key",
		.of_match_table = key_of_match,
	},
	.probe = key_probe,
	.remove = key_remove,
};


#if 1

static int __init mykey_init(void)
{
	return platform_driver_register(&key_drv);
}

static void __exit mykey_exit(void)
{
	platform_driver_unregister(&key_drv);
}

module_init(mykey_init);
module_exit(mykey_exit);

#else

module_platform_driver(pled_drv);

#endif

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("pinctrl test");
MODULE_ALIAS("pinctrl_led");
